package com.sinotrans.auth.controller;

import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.ConsumerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.sinotrans.auth.service.SecurityService;
import com.sinotrans.common.constant.Constant;
import com.sinotrans.common.entity.AuthClientProperties;
import com.sinotrans.common.entity.AuthProperties;
import com.sinotrans.common.rest.RestClient;
import com.sinotrans.common.security.AbstractSecurityController;
import com.sinotrans.common.security.AuthEntity;
import com.sinotrans.common.util.Utils;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

@Api(tags = "权限接口")
@PermitAll
@RefreshScope
@RestController
public class SecurityController extends AbstractSecurityController {

	@Autowired
	private SecurityService securityService;

	@Value(value = "${spring.application.name}")
	protected String securityServer;

	@Value(value = "${server.servlet.context-path:}")
	protected String securityServerContextpath;

	@Autowired
	protected AuthProperties authProperties;

	@Autowired
	protected RestTemplate restTemplate;

	@Autowired
	protected TokenStore tokenStore;

	@Autowired
	protected ConsumerTokenServices consumerTokenServices;

	@Override
	protected AuthEntity login(String username, String password) {
		AuthEntity authEntity = null;
		try {
			authEntity = securityService.login(username, password);
		} catch (Exception e) {
			logger.error("login error", e);
		}
		return authEntity;
	}

	@Override
	protected boolean logout(String username) {
		return true;
	}

	private MultiValueMap<String, String> authorizHttpHeaders(String clientinfo) {
		MultiValueMap<String, String> head = new LinkedMultiValueMap<String, String>();
		StringBuilder headBuilder = new StringBuilder();
		headBuilder.append("Basic").append(Constant.BLANK_STRING).append(clientinfo);
		head.add("Authorization", headBuilder.toString());
		return head;
	}

	/**
	 * 设置认证头部
	 * 
	 * @param authClientProperties
	 * @return
	 */
	protected MultiValueMap<String, String> getHttpHeaders(AuthClientProperties authClientProperties) {
		StringBuilder clientinfo = new StringBuilder();
		clientinfo.append(authClientProperties.getClientId()).append(Constant.COLON_STRING)
				.append(authClientProperties.getSecret());
		String base64Clientinfo = new String(Base64.getEncoder().encode(clientinfo.toString().getBytes()));
		return authorizHttpHeaders(base64Clientinfo);
	}

	@ApiOperation(value = "获取token")
	@RequestMapping(value = "/security/accessToken", method = { RequestMethod.POST, RequestMethod.GET })
	public OAuth2AccessToken accessToken(HttpServletRequest request, HttpServletResponse response,
			@RequestParam(required = false, value = "clientname", defaultValue = "web") String clientName,
			@RequestParam("username") String username, @RequestParam("password") String password) {
		OAuth2AccessToken token = null;
		try {
			//
			AuthClientProperties authEntity = authProperties.getAuthByName(clientName);
			MultiValueMap<String, String> head = getHttpHeaders(authEntity);
			//
			Map<String, String> param = new HashMap<String, String>();
			param.put("grant_type", "password");
			param.put("username", username);
			param.put("password", password);
			//
			String url = securityServer + securityServerContextpath + "/oauth/token";
			url = Utils.addUrlQuery(url, param);
			//
			token = RestClient.postForm(restTemplate, url, head, null, OAuth2AccessToken.class);
		} catch (Exception e) {
			logger.error("accessToken error", e);
		}
		return token;
	}

	@ApiOperation(value = "刷新token")
	@RequestMapping(value = "/security/refreshToken", method = { RequestMethod.POST, RequestMethod.GET })
	public OAuth2AccessToken refreshToken(HttpServletRequest request, HttpServletResponse response,
			@RequestParam("refresh_token") String refreshToken) {
		OAuth2AccessToken token = null;
		try {
			OAuth2RefreshToken oauth2RefreshToken = tokenStore.readRefreshToken(refreshToken);
			OAuth2Authentication oauth2Authentication = tokenStore
					.readAuthenticationForRefreshToken(oauth2RefreshToken);
			String clientid = oauth2Authentication.getOAuth2Request().getClientId();
			AuthClientProperties authEntity = authProperties.getAuthById(clientid);
			MultiValueMap<String, String> head = getHttpHeaders(authEntity);
			//
			Map<String, String> param = new HashMap<String, String>();
			param.put("grant_type", "refresh_token");
			param.put("refresh_token", refreshToken);
			//
			String url = securityServer + securityServerContextpath + "/oauth/token";
			url = Utils.addUrlQuery(url, param);
			//
			token = RestClient.postForm(restTemplate, url, head, null, OAuth2AccessToken.class);
		} catch (Exception e) {
			logger.error("refreshToken error", e);
		}
		return token;
	}

	@ApiOperation(value = "注销token")
	@RequestMapping(value = "/security/revokeToken", method = { RequestMethod.POST, RequestMethod.GET })
	public boolean revokeToken(HttpServletRequest request, HttpServletResponse response,
			@RequestParam("accessToken") String accessToken) {
		boolean resulte = false;
		try {
			OAuth2AccessToken oauth2AccessToken = tokenStore.readAccessToken(accessToken);
			consumerTokenServices.revokeToken(oauth2AccessToken.getValue());
			resulte = true;
		} catch (Exception e) {
			logger.error("revokeToken error", e);
		}
		return resulte;
	}

}
